"""
python p2_solution_sko_simulated_annealing.py
"""

import json
import numpy as np
from skopt import gp_minimize


# 加载仓库信息
with open('../fujian/fujian3/origin_data/warehouse.json', 'r') as f:
    warehouses = json.load(f)

# 加载平均库存量
with open('../fujian/fujian3/data_from_p1/all_average_inventory.json', 'r') as f:
    category_inventories = json.load(f)

# 加载平均销量
with open('../fujian/fujian3/data_from_p1/all_average_sales.json', 'r') as f:
    category_sales = json.load(f)

# 转换为字典以便快速访问
inventory_dict = {item['category_id']: item['average_inventory'] for item in category_inventories}
sales_dict = {item['category_id']: item['average_sales'] for item in category_sales}


def fitness_function(assignment):
    total_cost = 0
    warehouse_inventories = {warehouse['warehouse_id']: 0 for warehouse in warehouses}
    warehouse_sales = {warehouse['warehouse_id']: 0 for warehouse in warehouses}
    
    # 根据分配计算每个仓库的库存和销量
    for category_id, warehouse_id in zip(inventory_dict.keys(), assignment):
        inventory = inventory_dict[category_id]
        sales = sales_dict[category_id]
        
        warehouse_inventories[warehouse_id] += inventory
        warehouse_sales[warehouse_id] += sales
        
        if warehouse_id not in total_cost:
            total_cost += next((wh['daily_cost'] for wh in warehouses if wh['warehouse_id'] == warehouse_id), 0)
    
    # 检查约束
    for warehouse in warehouses:
        warehouse_id = warehouse['warehouse_id']
        if (warehouse_inventories[warehouse_id] >= warehouse['max_inventory'] or
            warehouse_sales[warehouse_id] >= warehouse['max_sales']):
            return float('inf')  # 违反约束，返回无穷大

    return total_cost

def fitness_function(assignment):
    total_cost = 0
    warehouse_inventories = {warehouse['warehouse_id']: 0 for warehouse in warehouses}
    warehouse_sales = {warehouse['warehouse_id']: 0 for warehouse in warehouses}
    
    # 根据分配计算每个仓库的库存和销量
    for category_id, warehouse_id in zip(inventory_dict.keys(), assignment):
        inventory = inventory_dict[category_id]
        sales = sales_dict[category_id]
        
        warehouse_inventories[warehouse_id] += inventory
        warehouse_sales[warehouse_id] += sales
        
        if warehouse_id not in total_cost:
            total_cost += next((wh['daily_cost'] for wh in warehouses if wh['warehouse_id'] == warehouse_id), 0)
    
    # 检查约束
    for warehouse in warehouses:
        warehouse_id = warehouse['warehouse_id']
        if (warehouse_inventories[warehouse_id] >= warehouse['max_inventory'] or
            warehouse_sales[warehouse_id] >= warehouse['max_sales']):
            return float('inf')  # 违反约束，返回无穷大

    return total_cost


# 获取仓库ID列表
warehouse_ids = [warehouse['warehouse_id'] for warehouse in warehouses]

# 定义初始化解，随机分配类别到仓库
initial_assignment = np.random.choice(warehouse_ids, size=len(inventory_dict))

# 设置优化参数
n_iterations = 1000

# 执行模拟退火
result = gp_minimize(
    fitness_function,
    [(0, len(warehouse_ids) - 1)] * len(inventory_dict),  # 对应每个品类的仓库选择
    n_calls=n_iterations,
    x0=initial_assignment
)

# 最优分配结果
optimal_assignment = result.x


# 生成最终分配结果
allocation_result = []
for category_id, warehouse_id in zip(inventory_dict.keys(), optimal_assignment):
    allocation_result.append({
        'category_id': category_id,
        'warehouse_id': warehouse_ids[warehouse_id]
    })

# 保存分配结果到 JSON
output_path = '../fujian/fujian3/solution_scikit_opt_simulated_annealing/allocation_result.json'
with open(output_path, 'w') as f:
    json.dump(allocation_result, f, indent=4)

# 计算总成本
total_cost = fitness_function(optimal_assignment)

# 保存总成本到文件
cost_output_path = '../fujian/fujian3/solution_scikit_opt_simulated_annealing/all_cost.txt'
with open(cost_output_path, 'w') as f:
    f.write(f'Total Cost: {total_cost}\n')

# 计算并保存库存和出货量利用率
utilization_inventory = []
utilization_sales = []
for warehouse in warehouses:
    warehouse_id = warehouse['warehouse_id']
    inventory_used = sum(inventory_dict[category_id] for category_id, wh_id in zip(inventory_dict.keys(), optimal_assignment) if wh_id == warehouse_id)
    sales_used = sum(sales_dict[category_id] for category_id, wh_id in zip(inventory_dict.keys(), optimal_assignment) if wh_id == warehouse_id)
    
    utilization_inventory.append({
        'warehouse_id': warehouse_id,
        'utilization_rate_of_inventory': inventory_used / warehouse['max_inventory'] if warehouse['max_inventory'] > 0 else 0
    })
    
    utilization_sales.append({
        'warehouse_id': warehouse_id,
        'utilization_rate_of_sales': sales_used / warehouse['max_sales'] if warehouse['max_sales'] > 0 else 0
    })

# 保存库存利用率到 JSON
utilization_inventory_path = '../fujian/fujian3/solution_scikit_opt_simulated_annealing/all_utilization_rate_inventory.json'
with open(utilization_inventory_path, 'w') as f:
    json.dump(utilization_inventory, f, indent=4)

# 保存出货量利用率到 JSON
utilization_sales_path = '../fujian/fujian3/solution_scikit_opt_simulated_annealing/all_utilization_rate_sales.json'
with open(utilization_sales_path, 'w') as f:
    json.dump(utilization_sales, f, indent=4)
